package org.paradigmshift.timelapse.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;


@SuppressWarnings( "serial" )
public class StripedJViewport extends JViewport {
	
	private static final Color EVEN_ROW_COLOR = new Color( 241, 245, 250 );
	
	private final JTable table;

	public StripedJViewport( JTable table ) {
		
		this.table = table;
		setOpaque( false );
		initListeners();
	}

	private void initListeners() {

		// install a listener to cause the whole table to repaint when
		// a column is resized. we do this because the extended grid
		// lines may need to be repainted. this could be cleaned up,
		// but for now, it works fine.
		PropertyChangeListener listener = new PropertyChangeListener() {

			public void propertyChange( PropertyChangeEvent evt ) {

				repaint();
			}
		};
		for (int i = 0; i < this.table.getColumnModel().getColumnCount(); i++) {
			this.table.getColumnModel().getColumn( i ).addPropertyChangeListener( listener );
		}
		
		// Add selection listener
		this.table.getSelectionModel().addListSelectionListener(
			new ListSelectionListener() {
				
				@Override
				public void valueChanged( ListSelectionEvent e ) {
					repaint();
				}
			}
		);
		
		this.table.addFocusListener(
			new FocusListener() {

				@Override
				public void focusGained( FocusEvent e ) {
					repaint();
				}

				@Override
				public void focusLost( FocusEvent e ) {
					repaint();
				}
			}
		);
		
		this.addMouseListener(
			new MouseListener() {

				@Override
				public void mouseClicked( MouseEvent e ) {
					Point point = e.getPoint();
					int row = table.rowAtPoint( point );
					table.getSelectionModel().setSelectionInterval( row, row );
				}

				@Override public void mousePressed( MouseEvent e ) {}
				@Override public void mouseReleased( MouseEvent e ) {}
				@Override public void mouseEntered( MouseEvent e ) {}
				@Override public void mouseExited( MouseEvent e ) {}
			}
		);
	}

	@Override
	protected void paintComponent( Graphics g ) {

		paintStripedBackground( g );
		paintVerticalGridLines( g );
		super.paintComponent( g );
	}

	private void paintStripedBackground( Graphics g ) {

		// get the row index at the top of the clip bounds (the first row
		// to paint).
		int rowAtPoint = this.table.rowAtPoint( g.getClipBounds().getLocation() );
		// get the y coordinate of the first row to paint. if there are no
		// rows in the table, start painting at the top of the supplied
		// clipping bounds.
		int topY = rowAtPoint < 0 ? g.getClipBounds().y : this.table.getCellRect( rowAtPoint, 0, true ).y;
		
		Point viewPosition = getViewPosition();
		g.translate( 0, -viewPosition.y );
		
		// create a counter variable to hold the current row. if there are
		// no
		// rows in the table, start the counter at 0.
		int currentRow = rowAtPoint < 0 ? 0 : rowAtPoint;
		while (topY < g.getClipBounds().y + g.getClipBounds().height) {
			int bottomY = topY + this.table.getRowHeight();
			g.setColor( getRowColor( currentRow ) );
			g.fillRect( g.getClipBounds().x, topY, g.getClipBounds().width, bottomY );
			topY = bottomY;
			currentRow++;
		}
		
		g.translate( 0, viewPosition.y );
	}
	
	private Color getRowColor( int row ) {
		
		if ( table.getSelectedRow() == row ) return table.getSelectionBackground();
		return row % 2 == 0 ? EVEN_ROW_COLOR : getBackground();
	}

	private void paintVerticalGridLines( Graphics g ) {

		// paint the column grid dividers for the non-existent rows.
		int offset = getViewPosition().x;
		int x = -offset;
		for (int i = 0; i < this.table.getColumnCount(); i++) {
			TableColumn column = this.table.getColumnModel().getColumn( i );
			// increase the x position by the width of the current column.
			x += column.getWidth();
			
			if ( x >= 0 ) {
				
				g.setColor( BetterJTable.TABLE_GRID_COLOR );
				// draw the grid line (not sure what the -1 is for, but
				// BasicTableUI
				// also does it.
				g.drawLine( x - 1, g.getClipBounds().y, x - 1, getHeight() );
			}
		}
	}
	
	@Override
	public void setViewPosition( Point p ) {
		
		super.setViewPosition( p );
		repaint();
	}
}
